import {
	PropsWithChildren,
	useCallback,
	useContext,
	useEffect,
	useLayoutEffect,
	useRef,
	useState
} from 'react';
import { Modal } from 'antd';
import { FormModalContext } from './FormModalContext';
import { useModalTitle, useUpdate } from './utils';
import { isEqual } from 'lodash-es';
import Draggable from 'react-draggable';
import type { DraggableData, DraggableEvent } from 'react-draggable';
import type { AnyObject, FormModalProps } from '../type';
import type { HookAPI } from 'antd/es/modal/useModal';

const ModalContainer = <T extends object = AnyObject>(
	props: PropsWithChildren<
		Required<
			Pick<FormModalProps<T>, 'form' | 'modalProps' | 'closeWarnProps' | 'fullscreen' | 'draggable'>
		>
	> & {
		full: boolean;
		setFull: (full: boolean) => void;
		closeModal: HookAPI;
	}
) => {
	const {
		form,
		modalProps = {},
		closeWarnProps,
		fullscreen = false,
		draggable = true,
		full,
		setFull,
		closeModal
	} = props;
	const { store, close, __INTERNAL__ } = useContext(FormModalContext);

	// 强制刷新
	const update = useUpdate();
	// 标记弹窗是否被打开过
	const openedRef = useRef(false);
	// 拖拽
	const draggleRef = useRef<HTMLDivElement>(null);
	const [disabled, setDisabled] = useState(true);
	const [bounds, setBounds] = useState({ left: 0, top: 0, bottom: 0, right: 0 });

	// 重置所有数据
	const resetData = () => {
		setFull(fullscreen);
		setDisabled(true);
		setBounds({ left: 0, top: 0, bottom: 0, right: 0 });
		form.resetFields();
	};

	// 初始化
	useEffect(() => {
		const { open, initData } = store;
		if (open && initData) {
			form.setFieldsValue(initData);
			openedRef.current = true;
		}
	}, [store.open]);

	useLayoutEffect(() => {
		__INTERNAL__(update);
	}, []);

	// Close
	const handleClose = () => {
		const { initData } = store;
		const values = form.getFieldsValue(true);
		// 对比目前表单值是否与初始值一致
		const same = isEqual(initData, values);
		// 相同直接关闭，不同则提示内容未保存
		if (same) {
			close();
		} else {
			closeModal.confirm({
				centered: true,
				title: '内容未保存，是否确认关闭？',
				onOk: close,
				...closeWarnProps
			});
		}
	};

	const titleNode = useModalTitle(props, store, full, disabled, setDisabled, setFull, handleClose);

	// 开始拖动
	const onDraggableStart = useCallback((_event: DraggableEvent, uiData: DraggableData) => {
		const { clientWidth, clientHeight } = window.document.documentElement;
		const targetRect = draggleRef.current?.getBoundingClientRect();
		if (!targetRect) return;
		setBounds({
			left: -targetRect.left + uiData.x,
			right: clientWidth - (targetRect.right - uiData.x),
			top: -targetRect.top + uiData.y,
			bottom: clientHeight - (targetRect.bottom - uiData.y)
		});
	}, []);

	return (
		<>
			<Modal
				destroyOnClose
				open={store.open}
				maskClosable={false}
				closable={false}
				afterClose={resetData}
				styles={{
					content: { padding: 0 },
					header: { padding: 16, margin: 0, borderBottom: '1px solid #eaeaea' },
					body: { padding: 0 }
				}}
				title={titleNode}
				modalRender={(modal) =>
					draggable && !full ? (
						<Draggable
							disabled={disabled}
							bounds={bounds}
							onStart={(event, uiData) => onDraggableStart(event, uiData)}
						>
							<div ref={draggleRef}>{modal}</div>
						</Draggable>
					) : (
						modal
					)
				}
				{...modalProps}
				footer={null}
				style={{ top: full ? 16 : null, ...modalProps.style }}
				width={full ? '100vw' : modalProps.width}
			>
				{props.children}
			</Modal>
		</>
	);
};

export default ModalContainer;
